# -*- coding: utf-8 -*-
"""
学习曲线
Created on Sun Apr  8 21:57:42 2018

@author: Allen
"""
import numpy as np
import matplotlib.pyplot as plt
np.random.seed( 42 ) # 添加一个随机种子
x = np.random.uniform( -3.0, 3.0, size = 100 )
X = x.reshape( -1, 1 )

y = 0.5 * x**2 + x + 2 + np.random.normal( 0, 1, size = 100 )
plt.scatter( x, y )
plt.show()

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split( X, y, random_state = 10 )

from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error

train_score = []
test_score = []

for i in range( 1, 76 ):
    lin_reg = LinearRegression()
    lin_reg.fit( X_train[:i], y_train[:i] )
    
    y_train_predict = lin_reg.predict( X_train[:i] )
    train_score.append( mean_squared_error( y_train[:i], y_train_predict[:i] ) )
    
    y_test_predict = lin_reg.predict( X_test )
    test_score.append( mean_squared_error( y_test, y_test_predict ) )

# 绘制两条曲线
plt.plot( [ i for i in range( 1, 76 ) ], np.sqrt( train_score ), label = "train" )
plt.plot( [ i for i in range( 1, 76 ) ], np.sqrt( test_score ), label = "test" )
plt.legend()
plt.show()

# 将以上代码封装成为一个函数
def plot_learning_curve( algo, X_train, X_test, y_train, y_test ):
    train_score = []
    test_score = []
    for i in range( 1, 76 ):
        algo.fit( X_train[:i], y_train[:i] )
        
        y_train_predict = algo.predict( X_train[:i] )
        train_score.append( mean_squared_error( y_train[:i], y_train_predict[:i] ) )
        
        y_test_predict = algo.predict( X_test )
        test_score.append( mean_squared_error( y_test, y_test_predict ) )

    # 绘制两条曲线
    plt.plot( [ i for i in range( 1, len( X_train ) + 1 ) ], np.sqrt( train_score ), label = "train" )
    plt.plot( [ i for i in range( 1, len( X_train ) + 1 ) ], np.sqrt( test_score ), label = "test" )
    plt.legend()
    plt.axis( [0, len( X_train ) + 1, 0, 4] )
    plt.show()
    
plot_learning_curve( LinearRegression(), X_train, X_test, y_train, y_test )
'''
需要注意的是两条曲线的距离
'''
'''
使用多项式回归来测试
'''
from sklearn.preprocessing import PolynomialFeatures
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline

def PolynomialRegression( degree ):
    return Pipeline([
            ( "poly", PolynomialFeatures( degree = degree ) ),
            ( "std_scaler", StandardScaler() ),
            ( "lin_reg", LinearRegression() )
            ])

poly2_reg = PolynomialRegression( 2 )
plot_learning_curve( poly2_reg, X_train, X_test, y_train, y_test )
'''
通过比较两张曲线图
    图1，误差稳定在了2.0左右
    图2，误差稳定在了1.2左右
    图2误差稳定的位置比较低，说明了拟合效果比较好
'''
poly3_reg = PolynomialRegression( 20 )
plot_learning_curve( poly3_reg, X_train, X_test, y_train, y_test )
'''
图3，可以看出，误差最后趋于稳定，
但是，训练误差曲线和测试误差曲线之间差距非常大，这就说明，模型在训练数据集上
拟合比较好，但是在测试数据集上，其误差依然很大。这种情况通常就是“过拟合”，
泛化能力不够。
'''

'''
总结：
    图1，欠拟合与图2最佳相比，图1两个数据集趋于稳定的位置，要高于图2的位置，
这就说明无论对于训练数据集来说，还是对于测试训练集来说误差都比较大，
这就说明模型选的就不对，所以在训练集上也是很大的。
    图3，过拟合这种情况，可以看出，在训练数据集上差距不大，和最佳情况的误差差不多
但是，测试数据集的误差是非常大的，距离训练数据集的误差非常大。
说明该模型的泛化能力不够好。对于新的数据来说，误差是比较大的。
'''




